#include "stdafx.h"
#include "PixelCalc.h"

PixelCalc::PixelCalc() {
}

PixelCalc::~PixelCalc() {
}

/*
 * Version 2: Beschleunigung der Schwellenwertberechnung
 * Zeitfenster (50x50) wird pro Durchlauf um eine Zeile/Spalte verschoben
 */
void PixelCalc::rasterOptimized(PixelStorage &pS) {
	for (int i = 0; i < (pS.grayImage.rows - 50); i++) {
		for (int j = 0; j < (pS.grayImage.cols - 50); j++) {
			pS.pixel = pS.grayImage.at<uchar>(i, j);

			pS.posY2 = i + 25;
			pS.posX2 = j + 25;

			if ((i - 25) >= 0) {
				pS.posY1 = i - 25;
			} else {
				pS.posY1 = 0;
			}
			if ((j - 25) >= 0) {
				pS.posX1 = j - 25;
			} else {
				pS.posX1 = 0;
			}
			minMaxHueOptimized(pS, i, j);
		}
	}
}

/*
 * Zeitfenster, min und max Wert berechnen
 * => Matrix Element auf 1 oder 0 setzen
 */
void PixelCalc::minMaxHueOptimized(PixelStorage &pS, int row, int col) {
	int lastCol = 0, lastRow = 0;
	double minValCol = 0, maxValCol = 0;

	pS.dx = pS.posX2 - pS.posX1;
	pS.dy = pS.posY2 - pS.posY1;

	Mat roiGrayImage(pS.grayImage, Rect(pS.posX1, pS.posY1, pS.dx, pS.dy));
		minMaxLoc(roiGrayImage, &pS.minVal, &pS.maxVal, 0, 0);
		
		if (row == 0) {
	minMaxLoc(roiGrayImage, &pS.minVal, &pS.maxVal, 0, 0);
	}
	else {
	lastRow = roiGrayImage.rows - 1;
		minMaxLoc(roiGrayImage.row(lastRow), &minValCol, &maxValCol, 0, 0);
		
		if ((minValCol < pS.minVal) && (maxValCol > pS.maxVal)) {
			pS.minVal = minValCol;
		pS.maxVal = maxValCol;
	}
	}

	if (col == 0) {
	minMaxLoc(roiGrayImage, &pS.minVal, &pS.maxVal, 0, 0);
	}
	else {
	lastCol = roiGrayImage.cols - 1;
		minMaxLoc(roiGrayImage.col(lastCol), &minValCol, &maxValCol, 0, 0);
		
		if ((minValCol < pS.minVal) && (maxValCol > pS.maxVal)) {
			pS.minVal = minValCol;
		pS.maxVal = maxValCol;
	}
	}

			if (((pS.maxVal - pS.minVal) > 100) && 
				(pS.pixel.val[0] >= ((pS.minVal + pS.maxVal) / 2))) {
		pS.binMatrix.at<int>(row, col) = 1;
		}
	else {
		pS.binMatrix.at<int>(row, col) = 0;
	}
}

/*
 * Konturbereich von 2D Objekten erfassen
 * orientation -> wahr, Rückgabe daher "signed value",
 * zur Bestimmung, ob Objekt im Uhrzeigersinn verlaeuft oder nicht
 */
void PixelCalc::contourArea(PixelStorage &pS) {
	bool orientation = true;
	vector<Point> contour;
	double area;

	int nContours = pS.objContours.size();
	for (int i = 0; i < nContours; i++) {
		contour = pS.objContours[i];
		area = cv::contourArea(contour, orientation);

#ifdef DEBUG_H_contourAre
		cout << "Contour area/Orientation: " << cArea << endl;
#endif
	}
}

/*
 * Konturlaenge der 2D Objekte berechnen
 * closed -> Erkennung, ob Kontur geschlossen oder nicht
 */
void PixelCalc::arcLength(PixelStorage &pS) {
	double cLength;
	bool closed = 0;
	vector<Point> contour;

	int nContours = pS.objContours.size();
	for (int i = 0; i < nContours; i++) {
		contour = pS.objContours[i];

		cLength = cv::arcLength(contour, closed);

#ifdef DEBUG_H_arcLength
		/*cout << "Contour length: " << cLength << endl;
		 cout << "Closed contour, yes/no: " << closed << endl;*/
#endif
	}
}

/*
 * Momente/Geometrische Eigenschaften von Objekten
 * ermitteln
 */
void PixelCalc::huMoments(PixelStorage &pS) {
	bool binImage = true;

	Moments m = moments(pS.objContours, binImage);
	Mat moments;

	HuMoments(m, moments);
}

void PixelCalc::calcTrueContours(PixelStorage &pS) {
	hull.resize(pS.objContours.size());
	defects.resize(pS.objContours.size());

	int nContours = pS.objContours.size();

	for (int i = 0; i < nContours; i++) {
		m = moments(pS.objContours[i]);
		HuMoments(m, getMoments);

		perimeter = cv::arcLength(pS.objContours[i], closed);
		approxPolyDP(pS.objContours[i], approx, 0.1 * perimeter, closed);

		area = cv::contourArea(approx);
		
			diameter = sqrt((4 * area) / M_PI);
			Ru = (diameter * M_PI) / pow(perimeter, 2);
			Ru = area / pow(perimeter, 2);
			//Extent
			rect = boundingRect(pS.objContours[i]);
			ratioRect = area / (rect.width * rect.height);

			//Solidity
			hullArea = cv::contourArea(pS.objContours[i]);
			solidity = area / hullArea;
			
			//Size prüfen, sonst Assertion Fehler
			if (pS.objContours[i].size() > 3) {
				convexHull(pS.objContours[i], hull[i]);
				convexityDefects(pS.objContours[i], hull[i], defects[i]);
			}

				if (defects[i].size() == 0) {
					if (solidity >= 0.7) {
						pS.trueContours.push_back(pS.objContours[i]);
					}
				}
	}

	cout << "Contour Count: " << pS.trueContours.size() << endl;
	drawTrueContours(pS);
}
